home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / DirectDraw / RefreshRate / refreshrate.cpp < prev    next >
C/C++ Source or Header  |  2001-10-31  |  28KB  |  771 lines

  1. //-----------------------------------------------------------------------------
  2. // File: RefreshRate.cpp
  3. //
  4. // Desc: This example demonstrates basic usage of the IDirectDraw7::StartRefreshRate
  5. //   and IDirectDraw7::EvaluateMode methods. Together, these methods allow an
  6. //   application to explore what display modes and refresh rates the monitor
  7. //   connected to this display device is able to display, through a manual
  8. //   user-controlled process. The application will present the UI that asks
  9. //   the user if the current mode under test is being displayed correctly by
  10. //   the monitor.
  11. //
  12. //   Applications should use these methods when they are interested in using
  13. //   higher refresh rates.
  14. //
  15. //   The basic idea is that DirectDraw will setup a list of modes to be tested
  16. //   (based on the list the app passed in), and then sequentially test them
  17. //   under application control. The app starts the test process, and then
  18. //   calls IDirectDraw7::EvaluateMode continuously. DirectDraw will take care
  19. //   of setting the modes. All the app has to do is SetCooperativeLevel
  20. //   beforehand, and then handle surface loss and drawing the UI that asks the
  21. //   user if they can see the current mode under test. DirectDraw returns
  22. //   enough information from IDirectDraw7::EvaluateMode to allow the app to
  23. //   know when to do these things, and when to stop testing. The app can pass
  24. //   a flag to IDirectDraw7::EvaluateMode if the user happened to say they
  25. //   could see the mode corretly, which will cause DirectDraw to mark the mode
  26. //   as good and move on. DirectDraw may also decide that time as run out and
  27. //   give up on a certain mode.
  28. //
  29. //   DirectDraw uses information at its disposal from any automated means to
  30. //   make the testing process as short as possible, and applications only need
  31. //   to test modes they are interested in.
  32. //
  33. // Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
  34. //-----------------------------------------------------------------------------
  35. #define STRICT
  36. #include <windows.h>
  37. #include <basetsd.h>
  38. #include <commdlg.h>
  39. #include <initguid.h>
  40. #include <ddraw.h>
  41. #include "resource.h"
  42.  
  43.  
  44.  
  45.  
  46. //-----------------------------------------------------------------------------
  47. // Function-prototypes
  48. //-----------------------------------------------------------------------------
  49. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  50. HRESULT GetDirectDrawDevices();
  51. VOID    OnInitDialog();
  52.  
  53. HRESULT ResetDeviceModes( DWORD dwDeviceIndex );
  54. HRESULT UpdateModesListBox( DWORD dwDeviceIndex );
  55.  
  56. BOOL    WINAPI DDEnumCallbackEx( GUID*, LPSTR, LPSTR, LPVOID, HMONITOR );
  57. HRESULT WINAPI EnumModesCallback( LPDDSURFACEDESC pddsd,  LPVOID pContext );
  58. HRESULT WINAPI EnumAllModesCallback( LPDDSURFACEDESC2 pddsd, LPVOID pContext );
  59.  
  60. HRESULT OnRefreshRate();
  61. HRESULT PerformDirectDrawRefreshRate( LPDIRECTDRAW7 pDD, SIZE* aTestModes, 
  62.                                    DWORD dwTestModes );
  63.  
  64.  
  65.  
  66.  
  67. //-----------------------------------------------------------------------------
  68. // Defines, constants, and global variables
  69. //-----------------------------------------------------------------------------
  70. #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
  71. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  72.  
  73. struct DDRAW_DEVICE_STRUCT
  74. {
  75.     GUID  guid;
  76.     CHAR  strDescription[256];
  77.     CHAR  strDriverName[64];
  78.     DWORD dwModeCount;
  79.     SIZE  aModeSize[256];
  80. };
  81.  
  82. HWND                g_hDlg  = NULL;
  83. LPDIRECTDRAW        g_pDD   = NULL;
  84.  
  85. DDRAW_DEVICE_STRUCT g_aDevices[16];
  86. DWORD               g_dwDeviceCount;
  87.  
  88.  
  89.  
  90.  
  91. //-----------------------------------------------------------------------------
  92. // Name: WinMain()
  93. // Desc: Entry point for the application.  Since we use a simple dialog for 
  94. //       user interaction we don't need to pump messages.
  95. //-----------------------------------------------------------------------------
  96. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, 
  97.                       INT nCmdShow )
  98. {
  99.     if( FAILED( GetDirectDrawDevices() ) )
  100.         return FALSE;
  101.  
  102.     // Display the main dialog box.
  103.     DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc );
  104.  
  105.     return TRUE;
  106. }
  107.  
  108.  
  109.  
  110.  
  111. //-----------------------------------------------------------------------------
  112. // Name: MainDlgProc()
  113. // Desc: Handles dialog messages
  114. //-----------------------------------------------------------------------------
  115. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  116. {
  117.     switch( msg ) 
  118.     {
  119.         case WM_INITDIALOG:
  120.             // Store HWND in global
  121.             g_hDlg = hDlg;
  122.  
  123.             OnInitDialog();
  124.             break;
  125.  
  126.         case WM_COMMAND:
  127.             switch( LOWORD(wParam) )
  128.             {
  129.                 case IDCANCEL:
  130.                     EndDialog( hDlg, IDCANCEL );
  131.                     break;
  132.  
  133.                 case IDC_TEST:
  134.                     if( FAILED( OnRefreshRate() ) )
  135.                     {
  136.                         MessageBox( g_hDlg, "Error doing starting mode test. "
  137.                                     "Sample will now exit.", "DirectDraw Sample", 
  138.                                     MB_OK | MB_ICONERROR );
  139.                         EndDialog( g_hDlg, IDABORT );
  140.                     }
  141.                     break;
  142.  
  143.                 case IDC_RESET:
  144.                     HWND hWndDeviceList;
  145.                     DWORD dwDeviceIndex;
  146.  
  147.                     // Get the currently selected DirectDraw device
  148.                     hWndDeviceList = GetDlgItem( hDlg, IDC_DDRAW_DEVICE_LIST );
  149.                     dwDeviceIndex = (DWORD)SendMessage( hWndDeviceList, LB_GETCURSEL, 0, 0 );
  150.  
  151.                     // Reset the modes for it
  152.                     if( FAILED( ResetDeviceModes( dwDeviceIndex ) ) )
  153.                     {
  154.                         MessageBox( g_hDlg, "Error reset DirectDraw device. "
  155.                                     "Sample will now exit.", "DirectDraw Sample", 
  156.                                     MB_OK | MB_ICONERROR );
  157.                         EndDialog( g_hDlg, IDABORT );
  158.                     }
  159.                     break;
  160.  
  161.                 case IDC_DDRAW_DEVICE_LIST:
  162.                     switch( HIWORD(wParam) )
  163.                     {
  164.                         case LBN_SELCHANGE:
  165.                             // Get the currently selected DirectDraw device
  166.                             DWORD dwDeviceIndex;
  167.                             dwDeviceIndex = (DWORD)SendMessage( (HWND) lParam, 
  168.                                                                 LB_GETCURSEL, 0, 0 );
  169.  
  170.                             // Update the list boxes using it 
  171.                             if( FAILED( UpdateModesListBox( dwDeviceIndex ) ) )
  172.                             {
  173.                                 MessageBox( g_hDlg, "Error enumerating DirectDraw modes."
  174.                                             "Sample will now exit.", "DirectDraw Sample", 
  175.                                             MB_OK | MB_ICONERROR );
  176.                                 EndDialog( g_hDlg, IDABORT );
  177.                             }
  178.  
  179.                             break;
  180.  
  181.                         default: 
  182.                             return FALSE;
  183.                     }
  184.                     break;
  185.  
  186.                 default:
  187.                     return FALSE; // Didn't handle message
  188.             }
  189.             break;
  190.  
  191.         default:
  192.             return FALSE; // Didn't handle message
  193.     }
  194.  
  195.     return TRUE; // Handled message
  196. }
  197.  
  198.  
  199.  
  200.  
  201. //-----------------------------------------------------------------------------
  202. // Name: GetDirectDrawDevices()
  203. // Desc: Retrieves all available DirectDraw devices and stores the information
  204. //       in g_aDevices[]
  205. //-----------------------------------------------------------------------------
  206. HRESULT GetDirectDrawDevices()
  207. {
  208.     return DirectDrawEnumerateEx( DDEnumCallbackEx, 
  209.                                   NULL,
  210.                                   DDENUM_ATTACHEDSECONDARYDEVICES |
  211.                                   DDENUM_DETACHEDSECONDARYDEVICES |
  212.                                   DDENUM_NONDISPLAYDEVICES );
  213. }
  214.  
  215.  
  216.  
  217.  
  218. //-----------------------------------------------------------------------------
  219. // Name: DDEnumCallbackEx()
  220. // Desc: Enumerates all available DirectDraw devices
  221. //-----------------------------------------------------------------------------
  222. BOOL WINAPI DDEnumCallbackEx( GUID* pGUID,    
  223.                               LPSTR strDriverDescription, 
  224.                               LPSTR strDriverName,        
  225.                               LPVOID pContext,           
  226.                               HMONITOR hm )       
  227. {
  228.     HRESULT hr;
  229.     LPDIRECTDRAW pDD = NULL;
  230.    
  231.     // Create a DirectDraw device using the enumerated guid 
  232.     hr = DirectDrawCreateEx( pGUID, (VOID**)&pDD, IID_IDirectDraw7, NULL );
  233.  
  234.     if( SUCCEEDED(hr) )
  235.     {
  236.         if( pGUID )
  237.         {
  238.             // Add it to the global storage structure
  239.             g_aDevices[ g_dwDeviceCount ].guid = *pGUID;
  240.         }
  241.         else
  242.         {
  243.             // Clear the guid from the global storage structure
  244.             ZeroMemory( &g_aDevices[ g_dwDeviceCount ].guid, 
  245.                         sizeof(GUID) );
  246.         }
  247.  
  248.         // Copy the description of the driver into the structure
  249.         lstrcpyn( g_aDevices[ g_dwDeviceCount ].strDescription, 
  250.                   strDriverDescription, 256 );
  251.         lstrcpyn( g_aDevices[ g_dwDeviceCount ].strDriverName, 
  252.                   strDriverName, 64 );
  253.  
  254.         // Retrive the modes this device can support
  255.         g_aDevices[ g_dwDeviceCount ].dwModeCount = 0;
  256.         hr = pDD->EnumDisplayModes( 0, NULL, NULL, EnumModesCallback );
  257.     
  258.         // Increase the counter for the number of devices found
  259.         g_dwDeviceCount++;
  260.  
  261.         // Release this device 
  262.         SAFE_RELEASE( pDD );
  263.     }
  264.  
  265.     // Continue looking for more devices
  266.     return TRUE;
  267. }
  268.  
  269.  
  270.  
  271.  
  272. //-----------------------------------------------------------------------------
  273. // Name: EnumModesCallback()
  274. // Desc: Enumerates the available modes for the device from which 
  275. //       EnumDisplayModes() was called.  It records the unique mode sizes in 
  276. //       the g_aDevices[g_dwDeviceCount].aModeSize array
  277. //-----------------------------------------------------------------------------
  278. HRESULT WINAPI EnumModesCallback( LPDDSURFACEDESC pddsd,  
  279.                                   LPVOID pContext )
  280. {
  281.     DWORD i;
  282.     DWORD dwModeSizeX;
  283.     DWORD dwModeSizeY;
  284.     DWORD dwModeCount;
  285.  
  286.     // For each mode, look through all previously found modes
  287.     // to see if this mode has already been added to the list
  288.     dwModeCount = g_aDevices[ g_dwDeviceCount ].dwModeCount;
  289.  
  290.     for( i = 0; i < dwModeCount; i ++ )
  291.     {
  292.         dwModeSizeX = g_aDevices[ g_dwDeviceCount ].aModeSize[i].cx;
  293.         dwModeSizeY = g_aDevices[ g_dwDeviceCount ].aModeSize[i].cy;
  294.  
  295.         if ( ( dwModeSizeX == pddsd->dwWidth ) &&
  296.              ( dwModeSizeY == pddsd->dwHeight ) )
  297.         {
  298.             // If this mode has been added, then stop looking
  299.             break;
  300.         }
  301.     }
  302.  
  303.     // If this mode was not in g_aDevices[g_dwDeviceCount].aModeSize[]
  304.     // then added it. 
  305.     if( i == g_aDevices[ g_dwDeviceCount ].dwModeCount )
  306.     {
  307.         g_aDevices[ g_dwDeviceCount ].aModeSize[i].cx = pddsd->dwWidth;
  308.         g_aDevices[ g_dwDeviceCount ].aModeSize[i].cy = pddsd->dwHeight;
  309.  
  310.         // Increase the number of modes found for this device
  311.         g_aDevices[ g_dwDeviceCount ].dwModeCount++;
  312.     }
  313.  
  314.     return TRUE;
  315. }
  316.  
  317.  
  318.  
  319.  
  320. //-----------------------------------------------------------------------------
  321. // Name: OnInitDialog()
  322. // Desc: Initializes the dialogs (sets up UI controls, etc.)
  323. //-----------------------------------------------------------------------------
  324. VOID OnInitDialog()
  325. {
  326.     // Load the icon
  327. #ifdef _WIN64
  328.     HINSTANCE hInst = (HINSTANCE) GetWindowLongPtr( g_hDlg, GWLP_HINSTANCE );
  329. #else
  330.     HINSTANCE hInst = (HINSTANCE) GetWindowLong( g_hDlg, GWL_HINSTANCE );
  331. #endif
  332.     HICON hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_ICON1 ) );
  333.  
  334.     // Set the icon for this dialog.
  335.     PostMessage( g_hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  336.     PostMessage( g_hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  337.  
  338.     // Show all available DirectDraw devices in the listbox
  339.     HWND hWndDeviceList = GetDlgItem( g_hDlg, IDC_DDRAW_DEVICE_LIST );
  340.     for( UINT i = 0; i < g_dwDeviceCount; i++ )
  341.     {
  342.         SendMessage( hWndDeviceList, LB_ADDSTRING, 0,
  343.             (LPARAM) g_aDevices[i].strDescription );
  344.         SendMessage( hWndDeviceList, LB_SETITEMDATA, i, (LPARAM) i);
  345.     }
  346.  
  347.     // Select the first device by default
  348.     DWORD dwCurrentSelect = 0;
  349.  
  350.     SendMessage( hWndDeviceList, LB_SETCURSEL, dwCurrentSelect, 0);
  351.     if( FAILED( UpdateModesListBox( dwCurrentSelect ) ) )
  352.     {
  353.         MessageBox( g_hDlg, "Error enumerating DirectDraw modes."
  354.                     "Sample will now exit.", "DirectDraw Sample", 
  355.                     MB_OK | MB_ICONERROR );
  356.         EndDialog( g_hDlg, IDABORT );
  357.     }
  358.  
  359.     SetFocus( hWndDeviceList );
  360. }
  361.  
  362.  
  363.  
  364.  
  365. //-----------------------------------------------------------------------------
  366. // Name: ResetDeviceModes()
  367. // Desc: If the user makes a mistake, and accidently says YES when a mode 
  368. //       cannot be seen, or NO when a mode really can be seen (thus ending up 
  369. //       with a lower refresh rate than possible) this allows the user to reset 
  370. //       the test results and try again.
  371. //-----------------------------------------------------------------------------
  372. HRESULT ResetDeviceModes( DWORD dwDeviceIndex )
  373. {
  374.     LPDIRECTDRAW7 pDD = NULL;
  375.     HRESULT       hr;    
  376.  
  377.     // Create a DirectDraw device based using the selected device guid
  378.     hr = DirectDrawCreateEx( &g_aDevices[dwDeviceIndex].guid, 
  379.                              (VOID**) &pDD, IID_IDirectDraw7, NULL);
  380.  
  381.     if( SUCCEEDED(hr) )
  382.     {
  383.         // Set the cooperative level to normal
  384.         if( SUCCEEDED( hr = pDD->SetCooperativeLevel( g_hDlg, DDSCL_NORMAL ) ) )
  385.         {
  386.             // Clear the previous mode tests
  387.             //
  388.             // We ignore the return code, since we would do nothing different on error returns.
  389.             // Note that most applications would never need to call StartRefreshRate this way.
  390.             // The reset functionality is intended to be used when a user accidentally accepted
  391.             // a mode that didn't actually display correctly.
  392.             pDD->StartModeTest( NULL, 0, 0 );
  393.         }
  394.  
  395.         // Release this device
  396.         SAFE_RELEASE( pDD ); 
  397.     }
  398.  
  399.     hr = UpdateModesListBox( dwDeviceIndex );
  400.  
  401.     return hr;
  402. }
  403.  
  404.  
  405.  
  406.  
  407. //-----------------------------------------------------------------------------
  408. // Name: UpdateModesListBox()
  409. // Desc: Updates the "modes to test" and "all modes" list boxes
  410. //-----------------------------------------------------------------------------
  411. HRESULT UpdateModesListBox( DWORD dwDeviceIndex )
  412. {
  413.     LPDIRECTDRAW7 pDD = NULL;
  414.     HRESULT       hr;    
  415.  
  416.     HWND hWndModesToTest = GetDlgItem( g_hDlg, IDC_TEST_MODES_LIST );
  417.     SendMessage( hWndModesToTest, LB_RESETCONTENT, 0, 0 );
  418.  
  419.     // Update the "modes to test" list box based on the display device selected
  420.     for( DWORD i = 0; i < g_aDevices[dwDeviceIndex].dwModeCount; i++ )
  421.     {
  422.         CHAR strMode[64];
  423.  
  424.         // Make a string based on the this mode's size
  425.         wsprintf( strMode, TEXT("%u x %u"),
  426.                   g_aDevices[dwDeviceIndex].aModeSize[i].cx, 
  427.                   g_aDevices[dwDeviceIndex].aModeSize[i].cy );
  428.  
  429.         // Add it to the list box
  430.         SendMessage( hWndModesToTest, LB_ADDSTRING, 0, (LPARAM) strMode );
  431.         SendMessage( hWndModesToTest, LB_SETITEMDATA, i, (LPARAM) i );
  432.     }
  433.  
  434.     // Create a DirectDraw device based using the selected device guid
  435.     if( SUCCEEDED( hr = DirectDrawCreateEx( &g_aDevices[dwDeviceIndex].guid, 
  436.                                          (VOID**) &pDD, IID_IDirectDraw7, NULL) ) )
  437.     {
  438.         HWND hWndAllModes = GetDlgItem( g_hDlg, IDC_ALL_MODES_LIST );
  439.         SendMessage( hWndAllModes, LB_RESETCONTENT, 0, 0 );
  440.  
  441.         // Enumerate and display all supported modes along
  442.         // with supported bit depth, and refresh rates 
  443.         // in the "All Modes" listbox
  444.         hr = pDD->EnumDisplayModes( DDEDM_REFRESHRATES, NULL,
  445.                                                 (VOID*) hWndAllModes, 
  446.                                                 EnumAllModesCallback );
  447.  
  448.         // Release this device
  449.         SAFE_RELEASE( pDD ); 
  450.     }
  451.  
  452.     return hr;
  453. }
  454.  
  455.  
  456.  
  457.  
  458. //-----------------------------------------------------------------------------
  459. // Name: EnumAllModesCallback()
  460. // Desc: For each mode enumerated, it adds it to the "All Modes" listbox.
  461. //-----------------------------------------------------------------------------
  462. HRESULT WINAPI EnumAllModesCallback( LPDDSURFACEDESC2 pddsd,  
  463.                                      LPVOID pContext )
  464. {
  465.     CHAR strMode[64];
  466.     HWND hWnd = (HWND) pContext;
  467.  
  468.     wsprintf( strMode, TEXT("%ux%ux%u - %u Hz"),
  469.               pddsd->dwWidth, 
  470.               pddsd->dwHeight,
  471.               pddsd->ddpfPixelFormat.dwRGBBitCount, 
  472.               pddsd->dwRefreshRate );
  473.  
  474.     SendMessage( hWnd, LB_ADDSTRING, 0, (LPARAM) strMode );
  475.  
  476.     return TRUE;
  477. }
  478.  
  479.  
  480.  
  481.  
  482. //-----------------------------------------------------------------------------
  483. // Name: OnRefreshRate()
  484. // Desc: User hit the "Test" button
  485. //-----------------------------------------------------------------------------
  486. HRESULT OnRefreshRate() 
  487. {
  488.     HWND hWndModesToTest = GetDlgItem( g_hDlg, IDC_TEST_MODES_LIST );
  489.     DWORD dwSelectCount = (DWORD)SendMessage( hWndModesToTest, LB_GETSELCOUNT, 0, 0 );
  490.  
  491.     if( dwSelectCount > 0 )
  492.     {
  493.         LPDIRECTDRAW7 pDD = NULL;
  494.         HRESULT       hr;    
  495.         HWND          hWndDeviceList;
  496.         DWORD         dwDeviceIndex;
  497.  
  498.         // Get the currently selected DirectDraw device
  499.         hWndDeviceList = GetDlgItem( g_hDlg, IDC_DDRAW_DEVICE_LIST );
  500.         dwDeviceIndex = (DWORD)SendMessage( hWndDeviceList, LB_GETCURSEL, 0, 0 );
  501.  
  502.         // Create a DirectDraw device based using the selected device guid
  503.         if( FAILED( hr = DirectDrawCreateEx( &g_aDevices[dwDeviceIndex].guid, 
  504.                                             (VOID**) &pDD, IID_IDirectDraw7, NULL) ) )
  505.             return hr;
  506.  
  507.         // This is a good usage of DDSCL_CREATEDEVICEWINDOW: DirectDraw will create a window that covers
  508.         // the monitor, and won't mess around with our dialog box. Any mouse clicks on the cover window
  509.         // will therefore not be received and misinterpreted by the dialog box, since such clicks will
  510.         // be sent to DirectDraw's internal message procedure and therein ignored.
  511.  
  512.         if( FAILED( hr = pDD->SetCooperativeLevel( g_hDlg,
  513.                                                DDSCL_EXCLUSIVE          | 
  514.                                                DDSCL_FULLSCREEN         |
  515.                                                DDSCL_CREATEDEVICEWINDOW | 
  516.                                                DDSCL_SETFOCUSWINDOW ) ) )
  517.         {
  518.             SAFE_RELEASE( pDD ); 
  519.             return hr;
  520.         }
  521.  
  522.  
  523.  
  524.         SIZE aTestModes[256];
  525.         DWORD dwTestModes = 0;
  526.  
  527.         // Find out which modes are selected, then just test those
  528.         for( DWORD i = 0; i < g_aDevices[dwDeviceIndex].dwModeCount; i++ )
  529.         {
  530.             if( SendMessage( hWndModesToTest, LB_GETSEL, i, 0 ) )
  531.             {
  532.                 // Record the selected modes in aTestModes[]
  533.                 aTestModes[dwTestModes] = g_aDevices[dwDeviceIndex].aModeSize[i];
  534.                 dwTestModes++;
  535.             }
  536.         }
  537.  
  538.         // Perform test on each of the selected modes on the selected device
  539.         hr = PerformDirectDrawRefreshRate( pDD, aTestModes, dwTestModes );
  540.  
  541.         // Release this device
  542.         SAFE_RELEASE( pDD ); 
  543.  
  544.         switch (hr)
  545.         {
  546.         case DDERR_NOMONITORINFORMATION:
  547.             // No EDID data is present for the current monitor.
  548.             MessageBox(g_hDlg,
  549.                 "The current monitor cannot be identified electronically.\n"
  550.                 "High refresh rates are not allowed on such monitors, so the test will not be performed.",
  551.                 "Testing Will Not Proceed", MB_OK | MB_ICONINFORMATION);
  552.             break;
  553.         case DDERR_NODRIVERSUPPORT:
  554.             // The driver cannot support refresh rate testing.
  555.             MessageBox(g_hDlg,
  556.                 "This driver does not support the refresh rate feature of DirectDraw.  Test cannot be performed.",
  557.                 "Testing Cannot Proceed", MB_OK | MB_ICONINFORMATION);
  558.             break;
  559.         default:
  560.             if( SUCCEEDED(hr) )
  561.             {
  562.                 MessageBox( g_hDlg, TEXT("Mode test completed"), TEXT("Result"), MB_OK );
  563.                 break;
  564.             }
  565.             else
  566.             {
  567.                 // A StartRefreshRate error occurred.
  568.                 MessageBox(g_hDlg,
  569.                 "StartRefreshRate returned an unexpected value when called with the DDSMT_ISTESTREQUIRED flag.",
  570.                 "StartRefreshRate Error", MB_OK | MB_ICONEXCLAMATION);
  571.                 return hr;
  572.             }
  573.         }
  574.  
  575.         // Update the mode list boxes based on the device selected
  576.         if( FAILED( hr = UpdateModesListBox( dwDeviceIndex ) ) )
  577.             return hr;
  578.     }
  579.     else
  580.     {
  581.         // There weren't any modes selected to test
  582.         MessageBox( g_hDlg, 
  583.                     TEXT("Select one or more modes to test from the list box"), 
  584.                     TEXT("No modes selected"), MB_OK );
  585.     }
  586.  
  587.     return S_OK;
  588. }
  589.  
  590.  
  591.  
  592.  
  593. //-----------------------------------------------------------------------------
  594. // Name: SetupPrimarySurface()
  595. // Desc: Setups a primary DirectDraw surface
  596. //-----------------------------------------------------------------------------
  597. HRESULT SetupPrimarySurface( LPDIRECTDRAW7 pDD, LPDIRECTDRAWSURFACE7* ppDDS )
  598. {
  599.     DDSURFACEDESC2 ddsd;
  600.  
  601.     ZeroMemory( &ddsd, sizeof(ddsd) );
  602.  
  603.     ddsd.dwSize         = sizeof(ddsd);
  604.     ddsd.dwFlags        = DDSD_CAPS;
  605.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  606.  
  607.     return pDD->CreateSurface(&ddsd, ppDDS, NULL);
  608. }
  609.  
  610.  
  611.  
  612.  
  613. //-----------------------------------------------------------------------------
  614. // Name: UpdatePrimarySurface()
  615. // Desc: Fills the primary surface with white, and diplays the timeout value
  616. //       on screen
  617. //-----------------------------------------------------------------------------
  618. HRESULT UpdatePrimarySurface( LPDIRECTDRAWSURFACE7 pDDS, DWORD dwTimeout )
  619. {
  620.     DDBLTFX ddbltfx;
  621.     HDC     hDC;
  622.     char    strTimeout[128];
  623.     RECT    rect;
  624.     HRESULT hr;
  625.   
  626.     // Clear the screen:  
  627.     ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
  628.     ddbltfx.dwSize      = sizeof(ddbltfx);
  629.     ddbltfx.dwFillColor = 0xFFFFFFFF;
  630.  
  631.     hr = pDDS->Blt( NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx );
  632.     if( FAILED( hr ) )
  633.         return hr;
  634.  
  635.     // Display the timeout value 
  636.     if( FAILED( hr = pDDS->GetDC( &hDC ) ) )
  637.         return hr;
  638.  
  639.     GetWindowRect( g_hDlg, &rect );
  640.     wsprintf( strTimeout, TEXT("Press space to accept or escape to reject. ")
  641.               TEXT("%2d seconds until timeout"), dwTimeout );
  642.     DrawText( hDC, strTimeout, strlen(strTimeout), &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
  643.  
  644.     // Cleanup
  645.     pDDS->ReleaseDC( hDC );
  646.  
  647.     return S_OK;
  648. }
  649.  
  650.  
  651.  
  652.  
  653. //-----------------------------------------------------------------------------
  654. // Name: PerformDirectDrawRefreshRate()
  655. // Desc: Perform the IDirectDraw7::StartRefreshRate and IDirectDraw7::EvaluateMode
  656. //       tests
  657. // Returns: S_OK if no modes needed testing, or all modes tested successfully,
  658. //          informative error code otherwise.
  659. //-----------------------------------------------------------------------------
  660. HRESULT PerformDirectDrawRefreshRate( LPDIRECTDRAW7 pDD, SIZE* aTestModes, 
  661.                                    DWORD dwTestModes )
  662. {
  663.     LPDIRECTDRAWSURFACE7 pDDSPrimary = NULL;
  664.     HRESULT hr;
  665.     MSG     msg;
  666.     DWORD   dwFlags = 0;
  667.     DWORD   dwTimeout;
  668.     BOOL    bMsgReady;
  669.  
  670.     // First call StartRefreshRate with the DDSMT_ISTESTREQUIRED flag to determine
  671.     // whether the tests can be performed and need to be performed.
  672.     hr = pDD->StartModeTest( aTestModes, dwTestModes, DDSMT_ISTESTREQUIRED);
  673.  
  674.     switch (hr)
  675.     {
  676.     case DDERR_NEWMODE:
  677.         // DDERR_NEWMODE means that there are modes that need testing.
  678.         break;
  679.     case DDERR_TESTFINISHED:
  680.         // DDERR_TESTFINISHED means that all the modes that we wish to test have already been tested correctly
  681.         return S_OK;
  682.     default:
  683.         //Possible return codes here include DDERR_NOMONITORINFORMATION or DDERR_NODRIVERSUPPORT or
  684.         //other fatal error codes (DDERR_INVALIDPARAMS, DDERR_NOEXCLUSIVEMODE, etc.)
  685.         return hr;
  686.     }
  687.  
  688.     hr = pDD->StartModeTest( aTestModes, dwTestModes, 0 );
  689.     if( hr == DDERR_TESTFINISHED )
  690.     {
  691.         // The tests completed early, so return
  692.         return S_OK;
  693.     }
  694.  
  695.     // Create the primary DirectDraw surface
  696.     if( FAILED( SetupPrimarySurface( pDD, &pDDSPrimary ) ) )
  697.         return hr;
  698.  
  699.     // Loop until the mode tests are complete
  700.     while( TRUE )
  701.     {
  702.         bMsgReady = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
  703.  
  704.         if( bMsgReady )
  705.         {
  706.             if (msg.message == WM_KEYDOWN)
  707.             {
  708.                 switch (msg.wParam)
  709.                 {
  710.                 case VK_SPACE:
  711.                     dwFlags = DDEM_MODEPASSED;
  712.                     break;
  713.  
  714.                 case VK_ESCAPE:
  715.                     dwFlags = DDEM_MODEFAILED;
  716.                     break;
  717.                 }
  718.             }
  719.             else
  720.             {
  721.                 TranslateMessage( &msg );
  722.                 DispatchMessage( &msg );
  723.             }
  724.         }
  725.         else
  726.         {
  727.             // This method will only succeed with monitors that contain EDID data. 
  728.             // If the monitor is not EDID compliant, then the method will return 
  729.             // DDERR_TESTFINISHED without testing any modes. If the EDID table does not 
  730.             // contain values higher than 60hz, no modes will tested. Refresh rates 
  731.             // higher than 100 hz will only be tested if the EDID table contains values 
  732.             // higher than 85hz.
  733.             hr = pDD->EvaluateMode(dwFlags, &dwTimeout);
  734.  
  735.             if( hr == DD_OK )
  736.             {
  737.                 if( pDDSPrimary )
  738.                 {
  739.                     // Clear the screen, and display the timeout value
  740.                     UpdatePrimarySurface( pDDSPrimary, dwTimeout );
  741.                 }
  742.             }
  743.             else if( hr == DDERR_NEWMODE )
  744.             {
  745.                 // Cleanup the last DirectDraw surface, and create
  746.                 // a new one for the new mode
  747.                 SAFE_RELEASE( pDDSPrimary );
  748.  
  749.                 if( FAILED( SetupPrimarySurface( pDD, &pDDSPrimary ) ) )
  750.                     return hr;
  751.  
  752.                 dwFlags = 0;
  753.             }
  754.             else if( hr == DDERR_TESTFINISHED )
  755.             {
  756.                 // Test complete, so stop looping
  757.                 break;
  758.             }
  759.  
  760.             Sleep( 100 );
  761.         }
  762.     }
  763.  
  764.     // Cleanup
  765.     SAFE_RELEASE( pDDSPrimary );
  766.  
  767.     return S_OK;
  768. }
  769.  
  770.  
  771.